from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework_jwt.settings import api_settings

from .utils import QQOauth
from .exceptions import QQOauthExcepiton
from .models import OAuthQQUser
from users.models import User
from . import serializers
from carts.utils import merge_cart_cookie_to_redis


class QQAuthURLView(APIView):
    """返回QQ扫码登录页面url"""

    def get(self, request):
        """获取QQ扫码登录页面url并返回"""
        # 获取查询字符串中的next参数(作用是登录成功后跳转到的地址)
        next = request.query_params.get('next')
        # 此处通过实例化QQ登录工具类并调用相关方法获取扫码页面url
        oauth = QQOauth(state=next)
        # 调用方法返回拼接好的扫码页面url
        login_url = oauth.oauth_login_url()

        return Response({'login_url': login_url})


class QQScanCodeView(GenericAPIView):
    """QQ扫码登录主过程"""
    # 指定所用的序列化器类
    serializer_class = serializers.QQLoginCheckSerializer

    def get(self, request):
        """获取code/access_token/openid"""
        # 从前端JS请求的url中获取查询字符串code
        code = request.query_params.get('code')
        # 判断是否获取到code，如果没有获取到code，则提示400Bad Request
        if not code:
            return Response({'message': '缺少code'}, status=status.HTTP_400_BAD_REQUEST)

        # 实例化工具类
        oauth = QQOauth()

        try:
            # 1.携带code请求QQ服务器请求access_token---面向逻辑思想
            access_token = oauth.get_access_token(code)
            # 2.携带access_token请求QQ服务器请求openid
            openid = oauth.get_openid(access_token)
        except QQOauthExcepiton:
            # 捕获接口处抛出的自定义异常并在响应中返回
            return Response({'message': 'QQ服务异常'}, status=status.HTTP_503_SERVICE_UNAVAILABLE)

        # 1.通过openid查询数据库，判断QQ用户是否是第一次登录
        try:
            oauth_user = OAuthQQUser.objects.get(openid=openid)
        except OAuthQQUser.DoesNotExist:
            # 2.第一次登录的话，则跳转到用户信息绑定页面
            access_token = QQOauth.generate_access_token(openid)
            # 将access_token返回给前端
            return Response({'access_token': access_token})
        else:
            # 3.不是第一次登录，则直接跳转到用户中心
            # 生成JWT token
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

            # 获取关联的user
            user = oauth_user.user

            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)

            # 组织要返回给前端的数据
            data = {
                'token': token,
                'user_id': user.id,
                'username': user.username
            }

            response = Response(data)

            # QQ非第一次登录,合并购物车数据
            response = merge_cart_cookie_to_redis(request=request, user=user, response=response)

            return response

    def post(self, request):
        """QQ登录绑定用户信息"""
        # 获取序列化器对象，并传入要进行校验的参数
        serializer = self.get_serializer(data=request.data)

        # 对参数进行校验
        serializer.is_valid(raise_exception=True)

        # 保存数据
        user = serializer.save()

        # 生成JWT token
        # 生成JWToken
        jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)

        # 添加token到user对象中
        user.token = token

        # 构造要返回的数据：token/user_id/username
        data = {
            'token': token,
            'user_id': user.id,
            'username': user.username
        }

        response = Response(data)

        # QQ第一次登录,绑定已有用户后合并购物车
        response = merge_cart_cookie_to_redis(request=request, user=user, response=response)

        return response
